package com.hotel.BL;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.EntityName;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.CompositeFilterOperator;
import com.google.appengine.api.datastore.Query.Filter;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.Query.FilterPredicate;

import data.General;
import data.Tax;

public class TaxLogic extends AbstractBL{
	
	public TaxLogic(HttpServletRequest req, HttpServletResponse resp)
	{
		this.req = req;
		this.resp = resp;
	}
	
	public List<Tax> GenerateTax(long hotelId)
	{
		List<Tax> list = new ArrayList<Tax>();
		
		Tax tax = new Tax();
		
		tax = new Tax();
		tax.setHotelId(hotelId);
		tax.setShortname("B");
		tax.setCurrencyValue((double) 50);
		tax.setCurrencyString("3519");
		tax.setIsOnRoomTariff(true);
		tax.setDescription("text tax per room tariff");
		tax.setAvaliable(true);
		tax.setStatus(true);
		tax.setSortOrder(0);
		list.add(tax);
		
		tax = new Tax();
		tax.setHotelId(hotelId);
		tax.setShortname("C");
		tax.setCurrencyValue((double) 20);
		tax.setCurrencyString("3519");
		tax.setIsOnRoomTariff(false);
		tax.setDescription("per reservation");
		tax.setAvaliable(true);
		tax.setStatus(true);
		tax.setSortOrder(0);
		list.add(tax);
		
		return list;
	}
	
	public Tax GetTax(long id)
	{
		Key key = KeyFactory.createKey(EntityName.Tax, id);
		try {
			Entity lang = datastore.get(key);
			Tax c = new Tax();
			c.setEntity(lang);
			return c;
		} catch (EntityNotFoundException e) {
			return null;
		}
	}
		
	
	public Tax GetTax(long hotelId,String Description)
	{
		Query q = new Query(EntityName.Tax);
		
		Filter filterHotel = new FilterPredicate("hotelId",FilterOperator.EQUAL,hotelId);
		Filter filterStatus = new FilterPredicate("status",FilterOperator.EQUAL,true);
		Filter filterAvaliable = new FilterPredicate("avaliable",FilterOperator.EQUAL,true);
		Filter filterTitle = new FilterPredicate("Description",FilterOperator.EQUAL,Description);

		Filter filter = CompositeFilterOperator.and(filterHotel, filterStatus, filterAvaliable,filterTitle);
		
		q.setFilter(filter);
		
		return GetTax(datastore.prepare(q).asSingleEntity());
	}
	
	public List<Tax> GetAllTax(long hotelId)
	{
		Query q = new Query(EntityName.Tax);
		
		Filter filterHotel = new FilterPredicate("HotelId",FilterOperator.EQUAL,hotelId);
		Filter filterStatus = new FilterPredicate("Status",FilterOperator.EQUAL,true);
		Filter filterAvaliable = new FilterPredicate("Avaliable",FilterOperator.EQUAL,true);

		Filter filter = CompositeFilterOperator.and(filterHotel, filterStatus, filterAvaliable);
		
		q.setFilter(filter);
		
		return GetList(datastore.prepare(q).asList(FetchOptions.Builder.withDefaults()));
	}
	
	public List<Tax> GetRoomTax(long hotelId)
	{
		Query q = new Query(EntityName.Tax);
		
		Filter filterHotel = new FilterPredicate("HotelId",FilterOperator.EQUAL,hotelId);
		//Filter filterRoomCharge = new FilterPredicate("isRoomCharge",FilterOperator.EQUAL,true);
		Filter filterStatus = new FilterPredicate("Status",FilterOperator.EQUAL,true);
		Filter filterAvaliable = new FilterPredicate("Avaliable",FilterOperator.EQUAL,true);

		Filter filter = CompositeFilterOperator.and(filterHotel, filterStatus, filterAvaliable/*,filterRoomCharge*/);
		
		q.setFilter(filter);
		
		return GetList(datastore.prepare(q).asList(FetchOptions.Builder.withDefaults()));
	}
	
	public Tax GetTax(Entity entity)
	{
		if(entity == null) return null;
		Tax item = new Tax();
		item.setEntity(entity);
		return item;
	}
	
	public List<Tax> GetList(List<Entity> entities)
	{
		List<Tax> list = new ArrayList<Tax>();
		for(Entity e : entities)
		{
			Tax a = new Tax();
			a.setEntity(e);
			list.add(a);
		}
		return list;
	}

	public Tax AddTax(long hotelId,String shortname,Double CurrencyValue,String currencyString,boolean IsOnRoomTariff,String description) throws EntityNotFoundException{
		Tax t = new Tax();
		t.setHotelId(hotelId);
		t.setShortname(shortname);
		t.setCurrencyValue(CurrencyValue);
		t.setCurrencyString(currencyString);
		t.setIsOnRoomTariff(IsOnRoomTariff);
		t.setDescription(description);
		t.setAvaliable(true);
		t.setStatus(true);
		t.setSortOrder(0);
		
		Key k = datastore.put(t.getEntity());
		t.setId(k.getId());
		t.setKey(k);

		return t;
	}
	
	public Tax EditTax(long taxId,String shortname,Double CurrencyValue,String currencyString,boolean IsOnRoomTariff,String description) throws EntityNotFoundException{
		Tax t = GetTax(taxId);
		t.setShortname(shortname);
		t.setCurrencyValue(CurrencyValue);
		t.setCurrencyString(currencyString);
		t.setIsOnRoomTariff(IsOnRoomTariff);
		t.setDescription(description);
		t.setSortOrder(0);

		Key k = datastore.put(t.getEntity());
		t.setId(k.getId());
		t.setKey(k);

		return t;
	}
	
	public Tax DeleteTax(long taxId) throws EntityNotFoundException{
		Tax t = GetTax(taxId);
		t.setAvaliable(false);
		t.setStatus(false);
		
		Key k = datastore.put(t.getEntity());
		t.setId(k.getId());
		t.setKey(k);

		return t;
	}
	
	public Tax ChangeStatus(long taxId) throws EntityNotFoundException{
		
		Tax a = GetTax(taxId);
		if(a.isStatus() == true){
			a.setStatus(false);
		}else if(a.isStatus() == false){
			a.setStatus(true);
		}
		 
		Key k = datastore.put(a.getEntity());
		a.setId(k.getId());
		a.setKey(k);

		return a;
	}
	
	//TODO: Will be delete - use new CalTax
	public Double CalTax(long hotelId,double cost){
		List<Tax> taxList = GetAllTax(hotelId);
		boolean includeTax;
		HttpSession session = req.getSession(true);
		if(session.getAttribute("isIncludetax") != null)
			includeTax = (Boolean)session.getAttribute("isIncludetax");
		else{
			GenericLogic genericLogic = new GenericLogic(req,resp);
			General general = genericLogic.GetGeneral(hotelId);
			includeTax = general.isIncloudetax();
		}
		double tax = 0.0;
		if(taxList != null){
			if(!includeTax){
				for(int i =0;i<taxList.size();i++){
					if(taxList.get(i).isIsOnRoomTariff()){
						tax += cost * (taxList.get(i).getCurrencyValue()/100);					
					}
//					else if(taxList.get(i).isIsPerReservation()){
//						tax += taxList.get(i).getCurrencyValue();	
//					}else if(taxList.get(i).isIsPerNight()){
//						tax += taxList.get(i).getCurrencyValue();	
//					}
				}
			}
		}
		return tax;
	}
	
	//Hashvalue : key - "costIncludeTax", "tax"
	//use HashMap<String,Double> calTax = taxLogic.CalRoomTax(hotelId,price,x);
	//calTax.get("costIncludeTax")
	public HashMap<String, Double> CalRoomTax(long hotelId,double cost,int index,boolean includeTax)
	{
		List<Tax> taxList = GetRoomTax(hotelId);
		HashMap<String,Double> returnValue = new HashMap<String,Double>();
		
		if(!includeTax){
			double price = cost;
			double tax = 0;
			for(int i =0;i<taxList.size();i++){
				if(taxList.get(i).isIsOnRoomTariff())
					tax += cost * (taxList.get(i).getCurrencyValue()/100);
//				else if(taxList.get(i).isIsPerReservation() && index == 0){
//					tax += taxList.get(i).getCurrencyValue();	
//				}else if(taxList.get(i).isIsPerNight()){
//					tax += taxList.get(i).getCurrencyValue();	
//				}
			}
			returnValue.put("costIncludeTax", (price + tax));
			returnValue.put("tax", tax);
			return returnValue;
		}
		else{
			double price = cost;
			double tax = 0;
			
			double k = 0;
			double perc = 0;
			for(int i =0;i<taxList.size();i++){
				if(taxList.get(i).isIsOnRoomTariff())
					perc += taxList.get(i).getCurrencyValue();
//				else if(taxList.get(i).isIsPerReservation() && index == 0){
//					k += taxList.get(i).getCurrencyValue();	
//				}else if(taxList.get(i).isIsPerNight()){
//					k += taxList.get(i).getCurrencyValue();	
//				}
			}
			
			double x_realprice = ((cost-k)*100) / (100+perc);
			tax = ((perc * x_realprice)/100) + k;
			
			returnValue.put("costIncludeTax", price);
			returnValue.put("tax", tax);
			return returnValue;
		}
	}
	
	public HashMap<String, Double> CalRoomTax(long hotelId,double cost,int index)
	{
		boolean includeTax;
		HttpSession session = req.getSession(true);
		if(session.getAttribute("isIncludetax") != null)
			includeTax = (Boolean)session.getAttribute("isIncludetax");
		else{
			GenericLogic genericLogic = new GenericLogic(req,resp);
			General general = genericLogic.GetGeneral(hotelId);
			includeTax = general.isIncloudetax();
		}
		return CalRoomTax(hotelId,cost,index,includeTax);
	}
	
	public Tax EditSortOrder(long id,long sortOrder) throws EntityNotFoundException{
		
		Tax a = GetTax(id);
		a.setSortOrder(sortOrder);
		 
		Key k = datastore.put(a.getEntity());
		a.setId(k.getId());
		a.setKey(k);

		return a;
	}
	
	public List<Tax> GetAllTax4AdminLimit(long hotelId,long offset,long line)
	{
		Query q = new Query(EntityName.Tax);
		
		Filter filterHotel = new FilterPredicate("HotelId",FilterOperator.EQUAL,hotelId);
		Filter filterAvaliable = new FilterPredicate("Avaliable",FilterOperator.EQUAL,true);

		Filter filter = CompositeFilterOperator.and(filterHotel, filterAvaliable);
		
		q.setFilter(filter);
		
		return GetList(datastore.prepare(q).asList(FetchOptions.Builder.withLimit((int) line).offset((int)offset)));
	}	
	
	public List<Tax> GetAllTax4Admin(long hotelId)
	{
		Query q = new Query(EntityName.Tax);
		
		Filter filterHotel = new FilterPredicate("HotelId",FilterOperator.EQUAL,hotelId);
		Filter filterAvaliable = new FilterPredicate("Avaliable",FilterOperator.EQUAL,true);

		Filter filter = CompositeFilterOperator.and(filterHotel, filterAvaliable);
		
		q.setFilter(filter);
		
		return GetList(datastore.prepare(q).asList(FetchOptions.Builder.withDefaults()));
	}
	
	public double GetTaxPerReservation(long hotelId)
	{
		Query q = new Query(EntityName.Tax);
		
		Filter filterHotel = new FilterPredicate("HotelId",FilterOperator.EQUAL,hotelId);
		Filter filterIsPerReservation = new FilterPredicate("IsPerReservation",FilterOperator.EQUAL,true);
		Filter filterAvaliable = new FilterPredicate("Avaliable",FilterOperator.EQUAL,true);

		Filter filter = CompositeFilterOperator.and(filterHotel,filterIsPerReservation, filterAvaliable);
		
		q.setFilter(filter);
		
		List<Tax> taxs = GetList(datastore.prepare(q).asList(FetchOptions.Builder.withDefaults()));
		double rs = 0;
		for(Tax t:taxs)
			rs+=t.getCurrencyValue();
		return rs;
	}

	public HashMap<String, Double> CalRoomTaxWithPolicy(long hotelId,double cost,boolean includeTax)
	{
		List<Tax> taxList = GetRoomTax(hotelId);
		HashMap<String,Double> returnValue = new HashMap<String,Double>();
		
		if(!includeTax){
			double price = cost;
			double tax = 0;
			for(int i =0;i<taxList.size();i++){
				if(taxList.get(i).isIsOnRoomTariff())
					tax += cost * (taxList.get(i).getCurrencyValue()/100);
			}
			returnValue.put("costIncludeTax", (price + tax));
			returnValue.put("tax", tax);
			return returnValue;
		}
		else{
			double price = cost;
			double tax = 0;
			double k = 0;
			double perc = 0;
			for(int i =0;i<taxList.size();i++){
				if(taxList.get(i).isIsOnRoomTariff())
					perc += taxList.get(i).getCurrencyValue();
			}
			double x_realprice = ((cost-k)*100) / (100+perc);
			tax = ((perc * x_realprice)/100) + k;
			
			returnValue.put("costIncludeTax", price);
			returnValue.put("tax", tax);
			return returnValue;
		}
	}

}
